home *** CD-ROM | disk | FTP | other *** search
- /* ====================================================================== */
-
- /* BindNames.c by Dave Haynie
-
- This is a simple utility to remove some of the drudgery of program
- installation. Instead of having to edit a Startup-Sequence for
- every logical name that must be used by a new program, this lets
- names be block-allocated. The BindNames program looks for files
- in the SYS:Names directory. Each of these files contains any number
- of lines of the form:
-
- Name: Path
-
- Where "Name" is the logical name we're assigning, "Path" is the
- path name we're making equivalent.
-
- improved by Jan Rembser 8.8.94:
- -multiple assigns ("Assign ADD")
- -for each assign one single path could be marked with a #,
- this path will be assigned first
- Bsp: Libs: sys:libs,sys:classes,sys:libs/libs2#
-
- it results in 'assign libs: sys:libs/libs2 sys:libs sys:classes'
- and not in 'assign libs: sys:libs sys:classes sys:libs/libs2'
-
- -extended verbosity with VVERBOSE (VV) means "very verbose"
- */
-
- #include <exec/types.h>
- #include <exec/memory.h>
- #include <exec/libraries.h>
- #include <dos/dos.h>
- #include <dos/dostags.h>
- #include <libraries/dosextens.h>
- #include <proto/all.h>
- #include <stdio.h>
- #include <ctype.h>
- #include <stdlib.h>
- #include <string.h>
-
- /* ====================================================================== */
-
- /* Macros */
-
- static char version[] = "\0$VER: BindNames 3.70 (17.08.94)";
- #define HELLO "BindNames by Dave Haynie, Dan Barrett and Jan Rembser"
-
- #define VERBOSE if (verbose) printf
- #define VVERBOSE if (veryverbose) printf
-
- #define CADDR(x) ((BPTR)(((ULONG)x)>>2))
- #define NAMEDIR "SYS:Names"
- #define NAMEDIRVAR "BindNamesDirectory"
- #define CopyStr(s) strcpy(malloc(strlen(s)+1),s)
- #define CatStr(s1,s2) strcat(strcat(strcpy(malloc(strlen(s1)+strlen(s2)+3),s1),","),s2)
- #define CatCom(s1,s2) strcat(strcat(strcpy(malloc(strlen(s1)+strlen(s2)+3),s1),s2),":")
- #define FreeStr(s) free(s)
-
- /* The "-rr" option doesn't like NewList, bit it's real simple. WHEN can
- we have inline functions.... */
-
- #define NewList(l) { (l)->lh_Head = (struct Node *)&(l)->lh_Tail; \
- (l)->lh_TailPred = (struct Node *)&(l)->lh_Head; \
- (l)->lh_Tail = NULL; \
- }
-
- /* ====================================================================== */
-
- /* Global variables */
-
- extern struct Library *SysBase; /* Use this to check the OS version number */
- extern struct DosLibrary *DosBase = NULL;
- struct DosInfo *info = NULL;
- struct DeviceList *lastdev;
- BPTR namelock = NULL;
- BOOL verbose = FALSE, veryverbose = FALSE, test = FALSE, adding = TRUE;
- struct FileInfoBlock *fileinfo = NULL;
- struct TagItem STags[4];
-
- /* ====================================================================== */
-
- /* Return the name of the BindNames name directory. */
-
- char *NameDir(char *argdir)
- {
- char *dir;
- static char default_dir[] = NAMEDIR;
-
- if (((dir = getenv(NAMEDIRVAR)) == NULL) && (!argdir))
- return(default_dir);
- else if (argdir) dir = argdir;
- return(dir);
- }
-
- /* ====================================================================== */
-
- void Hello(char *dir)
- {
- printf("\2337m%s\2330m\n", HELLO);
- printf("The current name directory is \"%s\"\n\n", NameDir(dir));
- }
-
- /* ====================================================================== */
-
- /* This function makes a BCPL string into a C style string. */
-
- char *b2cstr(char *cstr, BPTR bptr) {
- char *ptr = (char *)BADDR(bptr);
- strncpy(cstr,ptr+1,*ptr);
- cstr[*ptr] = '\0';
- return cstr;
- }
-
- /* This function allocates things in a DOS friendly way. */
-
- void *DOSAlloc(LONG size) {
- LONG *ptr = AllocMem(size+4,MEMF_PUBLIC|MEMF_CLEAR);
- *ptr = size+4;
- return ptr+1;
- }
-
- /* This function frees memory in a DOS friendly way. */
-
- void DOSFree(void *mem) {
- LONG *ptr = (LONG *)mem;
- FreeMem(ptr-1,*(ptr-1));
- }
-
- /* ====================================================================== */
-
- /* Here we manage name trees. Name nodes are built from the device list
- first. All primary nodes based on the device list have NULL paths,
- indicating that they are primary and thus, don't need to be recreated.
- Subsequent nodes are added to the node that they depend on. If a node
- is encountered that doesn't have a parent listed yet, it will be place
- on a temporary node list. */
-
- struct NameNode {
- struct Node node;
- struct NameNode *parent;
- struct List children;
- char *path;
- BOOL trymount;
- };
-
- struct List Names;
- struct NameNode *lostnodes;
-
- /* This function creates a name node, allocating whatever memory is
- needed. */
-
- struct NameNode *MakeNode(char *name, char *path) {
- struct NameNode *nn;
- int pathlen;
-
- if (!(nn = calloc(1,sizeof(struct NameNode)))) return NULL;
- if (name) nn->node.ln_Name = CopyStr(name);
- NewList(&nn->children);
- if (path){
- pathlen = strlen(path)-1;
- if (path[pathlen]=='#')
- path[pathlen]='\0';
- nn->path = CopyStr(path);
- }
- nn->trymount = FALSE;
- return nn;
- }
-
- /* This function finds a particular name in the Names data base, via a
- depth-first search. If it finds the name, it returns that node,
- otherwise, it returns NULL. */
-
- struct NameNode *FindNode(struct List *lst,char *name) {
- struct Node *n;
- struct NameNode *nn;
-
- for (n = lst->lh_Head; n->ln_Succ; n = n->ln_Succ) {
- if (!(stricmp(name,n->ln_Name))) return (struct NameNode *)n;
- if (nn = FindNode(&((struct NameNode *)n)->children,name)) return nn;
- }
- return NULL;
- }
-
- /* This function prints the whole Nametree */
-
- void PrintList(struct List* lst,char *title, UBYTE level){
- struct Node *n;
- struct NameNode *nn;
-
- if (veryverbose){
- if (level==0) printf("%s\n",title);
- for (n = lst->lh_Head; n->ln_Succ; n = n->ln_Succ) {
- nn = (struct NameNode *)n;
- printf("%s, ",nn->node.ln_Name);
- if (nn->children.lh_Head->ln_Succ){
- printf("\n%*s",level+2,"");
- PrintList(&nn->children,"--",level+2);
- printf("\n%*s",level,"");
- }
- }
- if (level==0) printf("\n\n");
- }
- }
-
- /* Strip trailing and heading spaces and tabs from a string. */
- void StripStr(char *str)
- {
- char *p;
- int len,i,offset=0;
-
- /* Do nothing to NULL strings and empty strings. */
- if (!str) return;
-
- len = strlen(str);
- if (len == 0) return;
-
- /* How many beginning stripchars ? */
- while ((str[offset] == ' ') || (str[offset] == '\t')) offset++;
-
- /* Move following chars to beginning of string */
- if (offset>1){
- i=0;
- while (i<len-offset) str[i] = str[offset+(i++)];
-
- /* overwrite old end with spaces */
- while (i<len) str[i++] = ' ';
- }
-
- /* Point at last character before the NULL. len is >= 1. */
- p = str + len - 1;
-
- /* Skip to the point ahead of all trailing space chars. */
- while ((p >= str) && (*p == ' ') || (*p == '\t')) p--;
-
- /* Whomp it. */
- *(++p) = '\0';
- }
-
- /* This is the node assignment routine. It accepts a node name and a path
- for assignment. It handles all the proper node creations to add that
- information to the node data base. */
-
- void DefNode(char *name, char *manypath) {
- struct NameNode *nn, *parent, *removed,
- *nnparent, *grandparent,
- *nnparent2;
- char pardev[64], *dummy, path[64];
- int i, last , pathlen;
- BOOL pathisfirst;
-
- for (i = 0; manypath[i] != ',' && manypath[i] != '\0' && i < 63; ++i) path[i] = manypath[i];
- path[i] = '\0';
- StripStr(path);
-
- last=i+1;
- while (path[0]!='\0'){
- for (i = 0; path[i] != ':' && i < 63; ++i) pardev[i] = path[i];
- pardev[i] = '\0';
- if (!(parent = FindNode(&Names,pardev))) {
- VVERBOSE("Device '%s:' from path '%s' not found!\n",pardev,path);
- AddHead(&lostnodes->children,(struct Node *)(parent=MakeNode(pardev,NULL)));
- parent->trymount = TRUE;
- parent->parent = parent;
- PrintList(&Names,"new parent enqueued:",0);
- }
-
- if (!(nn = FindNode(&Names,name))){
- nn = MakeNode(name,path);
- if (parent->trymount || parent->path)
- nn->parent = parent;
- else
- nn->parent = nn;
-
- VVERBOSE("New node '%s:' with path '%s'\n",name,path);
- AddHead(&parent->children,(struct Node *)nn);
- }
- else {
- removed = NULL;
- nnparent2 = nn;
- nnparent = nn;
- do
- {
- nnparent=nnparent->parent;
- grandparent=parent;
- do
- {
- grandparent=grandparent->parent;
- if (nnparent->node.ln_Name == grandparent->node.ln_Name){
- removed = nnparent2;
- }
- }while(grandparent->node.ln_Name != grandparent->parent->node.ln_Name);
- nnparent2=nnparent;
- }while(nnparent->node.ln_Name != nnparent->parent->node.ln_Name);
-
- if (!removed) removed = nnparent;
-
- if (parent->trymount || parent->path) removed->parent = parent;
- Remove((struct Node *)removed);
- VVERBOSE("Removed node: '%s:'\n",removed->node.ln_Name);
- PrintList(&Names,"removed:",0);
- AddHead(&parent->children,(struct Node *)removed);
-
- nn->trymount = FALSE;
-
- VVERBOSE("Path changed for: '%s:'\nfrom: '%s'\n",name,nn->path);
- pathlen = strlen(path)-1;
- if (path[pathlen]=='#'){
- path[pathlen]='\0';
- pathisfirst = TRUE;
- }
- else pathisfirst = FALSE;
-
- if (nn->path){
- if (pathisfirst){
- dummy = CatStr(path,nn->path);
- path[pathlen]=' ';
- }
- else
- dummy = CatStr(nn->path,path);
- FreeStr(nn->path);
- nn->path = dummy;
- }
- else
- nn->path = CopyStr(path);
- if (pathisfirst)
- path[pathlen]=' ';
- VVERBOSE(" to: '%s'\n\n",nn->path);
- }
- PrintList(&Names,"Node enqueued:",0);
- if (manypath[last-1] != '\0'){
- for (i = last; (manypath[i] != ',') && (manypath[i] != '\0') && (i-last < 63); ++i)
- path[i-last] = manypath[i];
-
- path[i-last] = '\0';
- last = i+1;
- StripStr(path);
- }
- else
- path[0] = '\0';
- }
- }
-
- /* This function reads in the individual file's data and builds entries
- in the name list based on that data. */
-
- void AddFIB(struct FileInfoBlock *fib,char *name) {
- BPTR file;
- char *buf,*com,*path;
-
- if (buf = AllocMem(fib->fib_Size+1,0L)) {
- if (file = Open(name,MODE_OLDFILE)) {
- Read(file,buf,fib->fib_Size);
- buf[fib->fib_Size] = '\0';
- com = strtok(buf,":\t\n");
- path = strtok(NULL,"\t\n");
- StripStr(com);
- StripStr(path);
- while (com && path) {
- if (com[0] != ';')
- DefNode(com,path);
-
- com = strtok(NULL,":\t\n");
- path = strtok(NULL,"\t\n");
- StripStr(com);
- StripStr(path);
- }
- Close(file);
- }
- FreeMem(buf,fib->fib_Size+1);
- }
- }
-
- /* ====================================================================== */
-
- /* This function opens up the stuff we need. */
-
- BOOL DoInits(void) {
- if (!(DosBase = (struct DosLibrary *)OpenLibrary("dos.library",33L)))
- return FALSE;
- if (!(info = (struct DosInfo *)BADDR(((struct RootNode *)DosBase->dl_Root)->rn_Info)))
- return FALSE;
- if (!(fileinfo = AllocMem(sizeof(struct FileInfoBlock),MEMF_PUBLIC)))
- return FALSE;
-
- return TRUE;
- }
-
- /* This function cleans up after DoInits. */
-
- void CloseUp(int code, char *str) {
- if (str) printf("Error: %s\n",str);
- if (fileinfo) FreeMem(fileinfo,sizeof(struct FileInfoBlock));
- if (namelock) UnLock(namelock);
- if (DosBase) CloseLibrary((struct Library *)DosBase);
- exit(code);
- }
-
- /* ====================================================================== */
-
- /* This function finds a directory node. It has the side effect of
- setting "lastdev" to the last device in the global device list. */
-
- struct DeviceList *AllocDirNode(char *name) {
- struct DeviceList *dev, *newdev;
- char *str,old[64];
-
- /* Let's see if the assignment has already been made... */
- for (dev = (struct DeviceList *)BADDR(info->di_DevInfo); dev != NULL;
- dev = (struct DeviceList *)BADDR(dev->dl_Next)) {
- lastdev = dev;
- if (dev->dl_Type != DLT_DIRECTORY) continue;
- b2cstr(old,dev->dl_Name);
- if (!stricmp(old,name))
- return dev;
- }
-
- /* Create the new name structure */
- if (!(newdev=DOSAlloc(sizeof(struct DeviceList))) || !(str=DOSAlloc(32L))) {
- if (newdev) DOSFree(newdev);
- return NULL;
- }
- newdev->dl_Type = DLT_DIRECTORY;
- strcpy(str+1,name);
- str[0] = strlen(name);
- newdev->dl_Name = CADDR(str);
- return newdev;
- }
-
- /* This function does the "Assign" operation. */
-
- BOOL Assign(char *name, char *path) {
- BPTR block;
- struct DeviceList *newdev;
- char old[64], *pathpart;
- BOOL oldchanged = FALSE;
-
- pathpart = strtok(path, ",");
-
- /* Let's verify that the path object is really there. If not, try to make
- the thing. */
- if (!(block = Lock(pathpart,SHARED_LOCK))) {
- if (!(block = CreateDir(pathpart))) return FALSE;
- UnLock(block);
- if (!(block = Lock(pathpart,SHARED_LOCK))) return FALSE;
- }
-
- /* Get a node for this assignment. */
- Forbid();
- newdev = AllocDirNode(name);
-
- /* Make the assignment */
- if (newdev->dl_Lock) {
- Permit();
- UnLock(newdev->dl_Lock);
- oldchanged = TRUE;
- VVERBOSE("Changing old assign '%s:' to '%s'\n",b2cstr(old, newdev->dl_Name),pathpart);
- }
- newdev->dl_Lock = block;
- newdev->dl_Task = ((struct FileLock *)BADDR(block))->fl_Task;
-
- if (!oldchanged){
- /* Now link it into the device list. */
- newdev->dl_Next = lastdev->dl_Next;
- lastdev->dl_Next = CADDR(newdev);
- Permit();
- }
-
- pathpart = strtok(NULL, ",");
- while (pathpart && adding){
- VVERBOSE("Adding '%s' to '%s:' ",pathpart,name);
-
- /* Let's verify that the path object is really there. If not, try to make
- the thing. */
- if (!(block = Lock(pathpart,SHARED_LOCK))) {
- if (!(block = CreateDir(pathpart))){
- VVERBOSE("failed!! (CreateDir)\n");
- return FALSE;
- }
- UnLock(block);
- if (!(block = Lock(pathpart,SHARED_LOCK))){
- VVERBOSE("failed!! (LockDir)\n");
- return FALSE;
- }
- }
- if (RemAssignList(name,block))
- VVERBOSE("(old multiassign removed) ");
-
- if (!AssignAdd(name, block))
- VVERBOSE("failed!!");
-
- VVERBOSE("\n");
-
- pathpart = strtok(NULL, ",");
- }
-
- return TRUE;
- }
-
- /* This list takes in a node list, and performs assignments for all non-primary
- nodes in the list, as long as "test" is FALSE. */
-
- void AssignList(struct List *lst, int level) {
- struct Node *n;
- struct NameNode *nn;
- char *command = "c:Mount ",
- *commandstr;
- long result = 0;
- BOOL dummytest = test,
- dummyverbose = verbose;
-
- for (n = lst->lh_Head; n->ln_Succ; n = n->ln_Succ) {
- nn = (struct NameNode *)n;
- if (nn->path) {
- VERBOSE("%*s%-20s%*s%s\2330m\n",level+1,"\23333m",nn->node.ln_Name,
- 14-level,"\23332m",nn->path);
- if (!test) Assign(nn->node.ln_Name,nn->path);
- }
- else if (nn->trymount){
- STags[0].ti_Tag = SYS_Input; STags[0].ti_Data = Input();
- STags[1].ti_Tag = SYS_Output; STags[1].ti_Data = Output();
- STags[2].ti_Tag = SYS_Asynch; STags[2].ti_Data = FALSE;
- STags[3].ti_Tag = TAG_DONE;
- commandstr = CatCom(command,nn->node.ln_Name);
- if (!test) result = SystemTagList(commandstr,STags);
- VVERBOSE("Mounting '%s', result = %d\n",nn->node.ln_Name,result);
- if (result != 0){
- test = TRUE;
- verbose = TRUE;
- printf("Warning: Can't Resolve Names:\n");
- }
- else
- VERBOSE("Assigned Names:\n");
- }
- if (nn->children.lh_Head->ln_Succ)
- AssignList(&nn->children,level+2);
-
- test = dummytest;
- verbose = dummyverbose;
- }
- }
-
- /* ====================================================================== */
-
- void main(int argc, char *argv[]) {
- char path[256], *dir = NULL;
- long i;
- struct NameNode *nn;
- struct DeviceList *dev;
- BOOL die = FALSE;
-
- if (!DoInits()) CloseUp(5,NULL);
-
- /* Check the command line. */
- for (i = 1; i < argc; ++i)
- switch (toupper(argv[i][0])) {
- case 'S':
- Assign("SYS",argv[++i]);
- break;
- case 'D':
- dir = argv[++i];
- break;
- case 'V':
- verbose = TRUE;
- if (toupper(argv[i][1])=='V')
- veryverbose = TRUE;
- break;
- case 'T':
- test = TRUE;
- verbose = TRUE;
- break;
- case 'N':
- adding = FALSE;
- break;
- case '?':
- die = TRUE;
- break;
- }
-
- if (die)
- {
- Hello(dir);
- printf("Usage: %s [[V]VERBOSE] [TEST] [NOADD] [DIR <namesdir>] [SYSTEM drive]\n",
- argv[0]);
- CloseUp(0,NULL);
- }
-
- if (verbose) Hello(dir);
-
- if (adding && (SysBase->lib_Version<36)){
- printf("Error: Release 2 (V36) or a later version of the OS is required for AssignAdds.\n");
- adding = FALSE;
- }
-
- /* Let's build the internal device list. We know this list is going to be
- a flat list; everything is primary, and thus hung from the root list. */
- NewList(&Names);
- Forbid();
- for (dev = (struct DeviceList *)BADDR(info->di_DevInfo); dev != NULL;
- dev = (struct DeviceList *)BADDR(dev->dl_Next)) {
- if (!(nn = MakeNode(b2cstr(path,dev->dl_Name),NULL)))
- continue;
- nn->parent = nn;
- AddHead(&Names,(struct Node *)nn);
- }
- Permit();
-
- /* I need to build the "lostnodes" node. In order to avoid name collisions,
- I make the name of this node '\0'. We never need to search for it by
- name... */
-
- AddTail(&Names,(struct Node *)(lostnodes = MakeNode("\0",NULL)));
- PrintList(&Names,"System List:",0);
-
- /* Here I build the list of required assignments by walking through the
- SYS:Names directory, and reading each file. */
-
- if ((namelock = Lock(NameDir(dir),SHARED_LOCK))) {
- Examine(namelock,fileinfo);
- while (ExNext(namelock,fileinfo) || IoErr() != ERROR_NO_MORE_ENTRIES) {
- if (fileinfo->fib_DirEntryType > 0) continue;
- strcat(strcat(strcpy(path,NameDir(dir)),"/"),fileinfo->fib_FileName);
- AddFIB(fileinfo,path);
- }
- }
-
- /* Now I've got everything; let's see what's actually here. */
-
- /* Remove((struct Node *)lostnodes);*/
-
- VERBOSE("Assigned Names:\n");
- AssignList(&Names,1);
- CloseUp(0,NULL);
- }
-